function Map(game){
	this.game = game;
	
	this.map = null;
	this.player = null;
	
	this.instances = [];
	this.doors = [];
	this.npcs = [];
	
	this.view = vec2(0, 0);
	this.viewS = game.viewS;
	
	this.page = 0;
	this.cursor = 0;
	
	this.loadMap();
}

Map.prototype.loadMap = function(){
	this.map = this.getDummyMap();
	
	this.addItem(vec2(9, 3), Tileset.items.gun, ItemFactory.getItem("gun", 0.7));
	this.addItem(vec2(9, 3), Tileset.items.armour, ItemFactory.getItem("armour", 1.0));
	this.addItem(vec2(10, 3), Tileset.items.amulet, ItemFactory.getItem("amulet"));
	
	var npc = this.addNPC(Tileset.charas.npc, vec2(13,3));
	npc.behaviour = 2; npc.createPath("RRURDRRDDLLDLUULLU");
	
	this.parseMap();
	
	this.player.loop();
	FOV.getFov(this.player.position, this, 6);
};

Map.prototype.addItem = function(position, tile, item){
	var item = new Item(position, tile, item); 
	item.mapManager = this;
	item.id = this.instances.length;
	
	this.instances.push(item);
	
	return item;
};

Map.prototype.addNPC = function(/*tile*/ tile, /*vec2*/ position){
	var npc = new NPC(tile, position);
	npc.mapManager = this;
	npc.id = this.instances.length;
	
	this.npcs.push(npc);
	this.instances.push(npc);
	
	return npc;
};

Map.prototype.getNPCAt = function(/*vec2*/ position){
	for (var i=0,len=this.npcs.length;i<len;i++){
		if (!this.npcs[i].inMap){
			this.npcs.splice(i,1);
			i--;
			continue;
		}
		
		if (this.npcs[i].position.equals(position))
			return this.npcs[i];
	}
	
	return null;
};

Map.prototype.setPlayer = function(x, y){
	this.player = new Player(Tileset.charas.hero, vec2(x,y));
	this.player.mapManager = this;
};

Map.prototype.parseWall = function(tile, x, y){
	if (tile.isWall && this.map[y + 1] && this.map[y + 1][x] != 0){
		var dt = Tileset.spaceShip.getById(this.map[y+1][x]);
		if (dt.isWall && tile.wf == dt.wf)
			tile = Tileset.spaceShip.wallCE; //Ceiling
	}
	
	return tile;
};

Map.prototype.parseFloor = function(tile, x, y){
	if (tile.multiF){
		var add = "";
		if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.isWall && this.map[y-1][x].t.isWall){
			add = "LU";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && (this.map[y-1][x].t.isWall || this.map[y-1][x].t.ff != tile.ff)){
			add = "U";
		}else if (this.map[y][x+1] != tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.isWall){
			add = "RU";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y-1][x].t.ff == tile.ff && this.map[y][x-1].t.isWall){
			add = "LC";
		}else if (this.map[y][x+1] != tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff){
			if (this.map[y][x+1] <= 0) return tile;
			add = "RC";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] != tile.id && this.map[y][x-1].t.isWall && this.map[y-1][x].t.ff == tile.ff){
			add = "LD";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] != tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff){
			if (this.map[y+1][x] <= 0) return tile;
			add = "D";
		}else if (this.map[y][x+1] != tile.id && this.map[y+1][x] != tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff){
			add = "RD";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff && this.map[y-1][x+1].t.isWall){
			add = "CUR";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff && this.map[y+1][x+1] != tile.id){
			if (this.map[y+1][x+1] <= 0) return tile;
			add = "CDR";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff && this.map[y-1][x-1].t.isWall){
			add = "CUL";
		}else if (this.map[y][x+1] == tile.id && this.map[y+1][x] == tile.id && this.map[y][x-1].t.ff == tile.ff && this.map[y-1][x].t.ff == tile.ff && this.map[y+1][x-1] != tile.id){
			if (this.map[y+1][x-1] <= 0) return tile;
			add = "CDL";
		}
		
		if (add != ""){
			tile = Tileset.spaceShip[tile.ff + add];
		}
	}
	
	return tile;
};

Map.prototype.createDoor = function(x, y){
	var door = vec2(x, y);
	var dir = 'h';
	if (this.map[y][x-1].t.isWall)
		dir = 'v';
	door.dir = dir;
	
	this.doors.push(door);
};

Map.prototype.crossDoor = function(/*Character*/ ins, /*vec2*/ dir){
	var door;
	for (var i=0,len=this.doors.length;i<len;i++){
		if (this.doors[i].equals(ins.position)){
			door = this.doors[i];
			i = len;
		}else if (this.doors[i].equals(ins.position.a, ins.position.b+1) && dir.b == 1){
			door = this.doors[i];
			i = len;
		}
	}
	
	if (!door) return false;
	
	if (door.dir == 'v'){
		if (dir.b == -1){
			ins.position.b = door.b - 2;
		}else if (dir.b == 1){
			ins.position.b = door.b + 1;
		}
	}else{
		if (dir.a == -1){
			ins.position.a = door.a - 1;
		}else if (dir.a == 1){
			ins.position.a = door.a + 1;
		}
	}
	
	return true;
};

Map.prototype.isSolid = function(x, y){
	if (!this.map[y]) return true;
	if (!this.map[y][x]) return true;
	if (this.map[y][x].t.isWall){
		if ((this.map[y][x].t.id >= 50 && this.map[y][x].t.id < 60) || (this.map[y+1][x].t.id >= 50 && this.map[y+1][x].t.id < 60)){
			return 2;
		}
		return 1;
	}
	return 0;
};

Map.prototype.getVisible = function(x, y){
	if (!this.map[y]) return 0;
	if (!this.map[y][x]) return 0;
	
	return this.map[y][x].v;
};

Map.prototype.parseMap = function(){
	for (var y=0,len=this.map.length;y<len;y++){
		for (var x=0,xlen=this.map[y].length;x<xlen;x++){
			var t = this.map[y][x];
			if (t == 0) continue;
			
			var parse = true;
			if (t == -1){
				this.setPlayer(x, y);
				t = this.map[y][x + 1];
			}else if (t >= 50 && t < 60){
				parse = false;
				this.createDoor(x, y);
			}
			
			var tile = Tileset.spaceShip.getById(t);
			if (parse){
				tile = this.parseWall(tile, x, y);
				tile = this.parseFloor(tile, x, y);
			}
			
			this.map[y][x] = {t: tile, v: 0};
		}
	}
};

Map.prototype.getDummyMap = function(){
	var p = -1;
	var w = 20;
	var x = 23; //Window room
	var y = 22; //Window space
	var D = 50; //Door
	
	var map = [
		[0,0,0,0,0,0,0,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,w,y,w,w,y,w,w,w,y,w,w,y,w,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,w,w,x,w,w,w,w,D,w,w,w,x,w,w,w,0,0,0,0,0],
		[0,0,0,0,0,0,0,0,0,0,0,0,0,w,2,w,0,0,0,0,0,0,0,0,0,0,0],
		[0,0,0,0,0,0,0,0,0,0,0,0,0,w,2,w,0,0,0,0,0,0,0,0,0,0,0],
		[0,0,w,w,w,w,w,w,w,w,w,w,0,w,2,w,0,w,w,w,w,w,w,w,0,0,0],
		[0,0,w,w,y,w,w,y,w,w,w,w,w,w,2,w,w,w,w,w,y,w,w,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,w,w,w,2,w,w,w,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,p,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,w,0,0,0],
		[0,0,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,w,0,0,0],
		[0,0,w,w,x,w,w,x,w,w,w,w,w,w,w,w,w,w,w,w,x,w,w,w,0,0,0],
	];
	
	return map;
};

Map.prototype.drawMap = function(){
	var yi = this.view.b;
	var ye = yi + this.viewS.b;
	if (ye > this.map.length) ye = this.map.length;
	
	var xi = this.view.a;
	var xe = xi + this.viewS.a;
	if (xe > this.map[0].length) xe = this.map[0].length;
	
	var p = this.player;
	
	for (var y=yi;y<ye;y++){
		for (var x=xi;x<xe;x++){
			var t = this.map[y][x];
			if (t == 0) continue;
			
			if (t.v == 2){
				var distX = Math.abs(x - p.position.a);
				var distY = Math.abs(y - p.position.b);
				var dist = (distX > distY)? distX : distY;
				if (dist <= 1) dist = 0;
				
				this.game.drawTile(t.t, x - xi, y - yi, false, dist / 1.5);
			}else if (t.v == 1){
				this.game.drawTile(t.t, x - xi, y - yi, false, -1);
			}
		}
	}
};

Map.prototype.setDark = function(){
	var yi = this.view.b;
	var ye = yi + this.viewS.b;
	if (ye > this.map.length) ye = this.map.length;
	
	var xi = this.view.a;
	var xe = xi + this.viewS.a;
	if (xe > this.map[0].length) xe = this.map[0].length;
	
	for (var y=yi;y<ye;y++){
		for (var x=xi;x<xe;x++){
			var t = this.map[y][x];
			if (t == 0) continue;
			if (t.v == 2){ t.v = 1; }
		}
	}
};

Map.prototype.inventoryNav = function(){
	var game = this.game;
	
	if (game.keys[37] == 1){
		this.page -= 1;
		game.keys[37] = 2;
	}else if (game.keys[38] == 1){
		this.cursor -= 1;
		game.keys[38] = 2;
	}else if (game.keys[39] == 1){
		this.page += 1;
		game.keys[39] = 2;
	}else if (game.keys[40] == 1){
		this.cursor += 1;
		game.keys[40] = 2;
	}else if (this.game.keys[88] == 1){
		this.player.inventory = false;
		this.game.keys[88] = 2;
	}
	
	if (this.cursor < 0) this.cursor = 8 + this.cursor;
	else if (this.cursor > 7) this.cursor -= 8;
	
	var mpage = Math.ceil(PlayerStats.pClass.itemSl / 8) - 1;
	if (this.page < 0) this.page = mpage;
	else if (this.page > mpage) this.page = 0;
};

Map.prototype.drawInventory = function(){
	var ctx = this.game.eng.ctx;
	
	ctx.fillStyle = "rgba(0,30,0,0.8)";
	ctx.strokeStyle = "white";
	
	var w = ctx.width - 300;
	var h = ctx.height - 180;
	
	ctx.fillRect(150,100,w,h);
	ctx.strokeRect(150,100,w,h);
	
	var y = 116;
	var x = 166;
	var w2 = (w - 32) / 2 - 8;
	var ps = PlayerStats;
	var page = this.page * 8;
	
	for (var i=0;i<8;i++){
		if (ps.items[i + page]){
			var item = ps.items[i + page];
			var tile = Tileset.items[item.name];
			
			this.game.drawTile(tile, x + 8, y + 8, true);
			
			ctx.fillStyle = "white";
			ctx.fillText(item.name, x + 48, y + 20);
			if (item.equipped)
				ctx.fillText('E', x + w2 - 24, y + 20);
			
			var r = Math.floor(255 - (item.status * 255));
			var g = Math.floor(item.status * 255);
			
			if (item.isL){
				var ef = item.effect;
				ctx.fillText(ef.description, x + 48, y + 40);
			}else{
				ctx.fillStyle = "rgb(" + r + ", " + g + ",0)";
				ctx.fillText("Status: " + (item.status * 100) + "%", x + 48, y + 40);
			}
			
			if (this.cursor == i){
				if (this.game.keys[68] == 1){ //D
					item.equipped = false;
					var at = Console.getArticle(item.name);
					Console.addMessage("You dropped " + at + " " + item.name, "yellow", "drop_" + item.name);
					var it = this.addItem(this.player.position.clone(), Tileset.items[item.tile], item); it.joker = true;
					ps.items.splice(i,1);
					this.game.keys[68] = 2;
					i--; continue;
				}else if (this.game.keys[13] == 1){ //Enter
					if (item.isA || item.isW || item.isL)
						this.player.equip(i, !item.equipped);
					this.game.keys[13] = 2;
				}
			}
		}
		
		ctx.strokeStyle = (this.cursor == i)? "yellow" : "white";
		ctx.strokeRect(x,y,w2,48);
		y += 64;
		if (i == 3){ y = 116; x = 174 + w2;} 
	}
	
	this.inventoryNav();
	
	var center = this.game.eng.ctx.width / 2;
	ctx.fillStyle = "white";
	ctx.textAlign = "center";
	ctx.fillText("Press [^/v] to navigate, [</>] to change page", center, 75 + h);
	ctx.fillText("[Enter] to equip/use, [D] to drop, [X] to exit", center, 95 + h);
};

Map.prototype.pickItemsNav = function(){
	var game = this.game;
	
	if (game.keys[37] == 1){
		this.cursor -= 4;
		game.keys[37] = 2;
	}else if (game.keys[38] == 1){
		this.cursor -= 1;
		game.keys[38] = 2;
	}else if (game.keys[39] == 1){
		this.cursor += 4;
		game.keys[39] = 2;
	}else if (game.keys[40] == 1){
		this.cursor += 1;
		game.keys[40] = 2;
	}
	
	if (this.cursor < 0) this.cursor = 8 + this.cursor;
	else if (this.cursor > 7) this.cursor -= 8;
};

Map.prototype.drawPickItems = function(){
	var ctx = this.game.eng.ctx;
	
	ctx.fillStyle = "rgba(0,30,0,0.8)";
	ctx.strokeStyle = "white";
	
	var w = ctx.width - 300;
	var h = ctx.height - 200;
	
	ctx.fillRect(150,100,w,h);
	ctx.strokeRect(150,100,w,h);
	
	var y = 116;
	var x = 166;
	var w2 = (w - 32) / 2 - 8;
	var ps = PlayerStats;
	 
	for (var i=0;i<8;i++){
		if (ps.steppedItems[i]){
			var item = ps.steppedItems[i].item.item;
			var tile = Tileset.items[item.name];
			
			this.game.drawTile(tile, x + 8, y + 8, true);
			
			ctx.fillStyle = "white";
			ctx.fillText(item.name, x + 48, y + 20);
			
			var r = Math.floor(255 - (item.status * 255));
			var g = Math.floor(item.status * 255);
			
			if (item.isL){
				var ef = item.effect;
				ctx.fillText(ef.description, x + 48, y + 40);
			}else{
				ctx.fillStyle = "rgb(" + r + ", " + g + ",0)";
				ctx.fillText("Status: " + (item.status * 100) + "%", x + 48, y + 40); 
			}
						
			if (this.cursor == i && this.game.keys[13] == 1){
				this.player.pickItem(ps.steppedItems[i].item, i);
				this.game.keys[13] = 2;
			}
		}
		
		ctx.strokeStyle = (this.cursor == i)? "yellow" : "white";
		ctx.strokeRect(x,y,w2,48);
		y += 64;
		if (i == 3){ y = 116; x = 174 + w2;} 
	}
	
	if (ps.steppedItems.length == 0 || this.game.keys[27] == 1){
		this.player.multiItems = false;
	}
	
	ctx.fillStyle = "white";
	ctx.textAlign = "center";
	ctx.fillText("Press [Enter] to pick, [Esc] to exit", 166 + w / 2, 95 + h);
	
	this.pickItemsNav();
};

Map.prototype.setViewToPlayer = function(){
	var xi = Math.round(this.player.position.a - (this.viewS.a / 2));
	var yi = Math.round(this.player.position.b - (this.viewS.b / 2));
	
	if (yi < 0) yi = 0;
	if (xi < 0) xi = 0;
	
	this.view.set(xi, yi);
};

Map.prototype.execute = function(){
	this.drawMap();
	
	for (var i=0,len=this.instances.length;i<len;i++){
		if (!this.instances[i]) continue;
		
		if (!this.instances[i].inMap){
			this.instances.splice(i,1);
			i--;
		}else{
			this.instances[i].loop();
		}
	}
	
	this.player.loop();
	
	if (this.player.multiItems){
		this.drawPickItems();
	}else if (this.player.inventory){
		this.drawInventory();
	}
};
